package com.smart.community.commons.utils;

import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 批量查询工具类
 * 批量查询优化 - 分批处理
 * 
 * @author Wu.Liang
 * @since 2024-12-21
 */
@Slf4j
public class BatchQueryUtils {
    
    private static final Executor executor = Executors.newFixedThreadPool(10);
    
    /**
     * 批量查询
     * 
     * @param ids ID列表
     * @param queryFunction 查询函数
     * @param batchSize 批次大小
     * @param <T> 数据类型
     * @return 查询结果列表
     */
    public static <T> List<T> batchQuery(List<Long> ids, Function<List<Long>, List<T>> queryFunction, int batchSize) {
        if (ids == null || ids.isEmpty()) {
            return new ArrayList<>();
        }
        
        List<T> results = new ArrayList<>();
        
        // 分批处理
        for (int i = 0; i < ids.size(); i += batchSize) {
            int endIndex = Math.min(i + batchSize, ids.size());
            List<Long> batchIds = ids.subList(i, endIndex);
            
            try {
                List<T> batchResults = queryFunction.apply(batchIds);
                if (batchResults != null) {
                    results.addAll(batchResults);
                }
            } catch (Exception e) {
                log.error("批量查询失败，批次：{}，错误：{}", batchIds, e.getMessage(), e);
            }
        }
        
        return results;
    }
    
    /**
     * 异步批量查询
     * 
     * @param ids ID列表
     * @param queryFunction 查询函数
     * @param batchSize 批次大小
     * @param <T> 数据类型
     * @return 查询结果列表
     */
    public static <T> List<T> asyncBatchQuery(List<Long> ids, Function<List<Long>, List<T>> queryFunction, int batchSize) {
        if (ids == null || ids.isEmpty()) {
            return new ArrayList<>();
        }
        
        // 分批
        List<List<Long>> batches = new ArrayList<>();
        for (int i = 0; i < ids.size(); i += batchSize) {
            int endIndex = Math.min(i + batchSize, ids.size());
            batches.add(ids.subList(i, endIndex));
        }
        
        // 异步查询
        List<CompletableFuture<List<T>>> futures = batches.stream()
                .map(batch -> CompletableFuture.supplyAsync(() -> {
                    try {
                        return queryFunction.apply(batch);
                    } catch (Exception e) {
                        log.error("异步批量查询失败，批次：{}，错误：{}", batch, e.getMessage(), e);
                        return new ArrayList<T>();
                    }
                }, executor))
                .collect(Collectors.toList());
        
        // 等待所有查询完成
        List<T> results = new ArrayList<>();
        for (CompletableFuture<List<T>> future : futures) {
            try {
                List<T> batchResults = future.get();
                if (batchResults != null) {
                    results.addAll(batchResults);
                }
            } catch (Exception e) {
                log.error("获取异步查询结果失败：{}", e.getMessage(), e);
            }
        }
        
        return results;
    }
    
    /**
     * 去重批量查询
     * 
     * @param ids ID列表
     * @param queryFunction 查询函数
     * @param batchSize 批次大小
     * @param <T> 数据类型
     * @return 去重后的查询结果列表
     */
    public static <T> List<T> batchQueryDistinct(List<Long> ids, Function<List<Long>, List<T>> queryFunction, int batchSize) {
        List<T> results = batchQuery(ids, queryFunction, batchSize);
        Set<T> distinctSet = new LinkedHashSet<>(results);
        return new ArrayList<>(distinctSet);
    }
    
    /**
     * 分组批量查询
     * 
     * @param ids ID列表
     * @param queryFunction 查询函数
     * @param batchSize 批次大小
     * @param groupByFunction 分组函数
     * @param <T> 数据类型
     * @param <K> 分组键类型
     * @return 分组结果Map
     */
    public static <T, K> Map<K, List<T>> batchQueryGrouped(List<Long> ids, 
                                                          Function<List<Long>, List<T>> queryFunction, 
                                                          int batchSize,
                                                          Function<T, K> groupByFunction) {
        List<T> allResults = batchQuery(ids, queryFunction, batchSize);
        return allResults.stream()
                .collect(Collectors.groupingBy(groupByFunction));
    }
    
    /**
     * 带缓存的批量查询
     * 
     * @param ids ID列表
     * @param queryFunction 查询函数
     * @param cacheFunction 缓存函数
     * @param batchSize 批次大小
     * @param <T> 数据类型
     * @return 查询结果列表
     */
    public static <T> List<T> batchQueryWithCache(List<Long> ids, 
                                                 Function<List<Long>, List<T>> queryFunction, 
                                                 Function<Long, T> cacheFunction, 
                                                 int batchSize) {
        if (ids == null || ids.isEmpty()) {
            return new ArrayList<>();
        }
        
        List<T> results = new ArrayList<>();
        List<Long> uncachedIds = new ArrayList<>();
        
        // 先从缓存获取
        for (Long id : ids) {
            try {
                T cached = cacheFunction.apply(id);
                if (cached != null) {
                    results.add(cached);
                } else {
                    uncachedIds.add(id);
                }
            } catch (Exception e) {
                log.warn("从缓存获取数据失败，ID：{}，错误：{}", id, e.getMessage());
                uncachedIds.add(id);
            }
        }
        
        // 查询未缓存的数据
        if (!uncachedIds.isEmpty()) {
            List<T> uncachedResults = batchQuery(uncachedIds, queryFunction, batchSize);
            results.addAll(uncachedResults);
        }
        
        return results;
    }
    
    /**
     * 验证ID列表
     * 
     * @param ids ID列表
     * @return 是否有效
     */
    public static boolean validateIds(List<Long> ids) {
        return ids != null && !ids.isEmpty() && ids.stream().allMatch(Objects::nonNull);
    }
    
    /**
     * 将逗号分隔的ID字符串转换为Long列表
     * 
     * @param idString 逗号分隔的ID字符串
     * @return Long列表
     */
    public static List<Long> parseIds(String idString) {
        if (!StringUtils.hasText(idString)) {
            return new ArrayList<>();
        }
        
        return Arrays.stream(idString.split(","))
                .map(String::trim)
                .filter(StringUtils::hasText)
                .map(Long::valueOf)
                .collect(Collectors.toList());
    }
    
    /**
     * 获取默认批次大小
     * 
     * @return 默认批次大小
     */
    public static int getDefaultBatchSize() {
        return 100;
    }
    
    /**
     * 获取小批次大小（用于小数据量查询）
     * 
     * @return 小批次大小
     */
    public static int getSmallBatchSize() {
        return 50;
    }
    
    /**
     * 获取大批次大小（用于大数据量查询）
     * 
     * @return 大批次大小
     */
    public static int getLargeBatchSize() {
        return 500;
    }
}
